home *** CD-ROM | disk | FTP | other *** search
/ Programming an RTS Game with Direct3D / Programming an RTS Game with Direct3D.iso / Examples / Chapter 4 / Example 4.7 / terrain.cpp < prev    next >
Encoding:
C/C++ Source or Header  |  2006-07-01  |  7.8 KB  |  293 lines

  1. #include "terrain.h"
  2.  
  3. const DWORD TERRAINVertex::FVF = D3DFVF_XYZ | D3DFVF_NORMAL | D3DFVF_TEX2;
  4.  
  5. //////////////////////////////////////////////////////////////////////////////////////////
  6. //                                    PATCH                                                //
  7. //////////////////////////////////////////////////////////////////////////////////////////
  8.  
  9. PATCH::PATCH()
  10. {
  11.     m_pDevice = NULL;
  12.     m_pMesh = NULL;
  13. }
  14. PATCH::~PATCH()
  15. {
  16.     Release();
  17. }
  18.  
  19. void PATCH::Release()
  20. {
  21.     if(m_pMesh != NULL)
  22.         m_pMesh->Release();
  23.     m_pMesh = NULL;
  24. }
  25.  
  26. HRESULT PATCH::CreateMesh(HEIGHTMAP &hm, RECT source, IDirect3DDevice9* Dev)
  27. {
  28.     if(m_pMesh != NULL)
  29.     {
  30.         m_pMesh->Release();
  31.         m_pMesh = NULL;
  32.     }
  33.  
  34.     try
  35.     {
  36.         m_pDevice = Dev;
  37.  
  38.         int width = source.right - source.left;
  39.         int height = source.bottom - source.top;
  40.         int nrVert = (width + 1) * (height + 1);
  41.         int nrTri = width * height * 2;
  42.  
  43.         if(FAILED(D3DXCreateMeshFVF(nrTri, nrVert, D3DXMESH_MANAGED, TERRAINVertex::FVF, m_pDevice, &m_pMesh)))
  44.         {
  45.             debug.Print("Couldn't create mesh for PATCH");
  46.             return E_FAIL;
  47.         }
  48.  
  49.         //Create vertices
  50.         TERRAINVertex* ver = 0;
  51.         m_pMesh->LockVertexBuffer(0,(void**)&ver);
  52.         for(int z=source.top, z0 = 0;z<=source.bottom;z++, z0++)
  53.             for(int x=source.left, x0 = 0;x<=source.right;x++, x0++)
  54.             {
  55.                 D3DXVECTOR3 pos = D3DXVECTOR3(x, hm.m_pHeightMap[x + z * hm.m_size.x], -z);
  56.                 D3DXVECTOR2 alphaUV = D3DXVECTOR2(x / (float)hm.m_size.x, z / (float)hm.m_size.y);        //Alpha UV
  57.                 D3DXVECTOR2 colorUV = alphaUV * 8.0f;                                                    //Color UV
  58.                 ver[z0 * (width + 1) + x0] = TERRAINVertex(pos, alphaUV, colorUV);
  59.             }
  60.         m_pMesh->UnlockVertexBuffer();
  61.  
  62.         //Calculate Indices
  63.         WORD* ind = 0;
  64.         m_pMesh->LockIndexBuffer(0,(void**)&ind);    
  65.         int index = 0;
  66.  
  67.         for(int z=source.top, z0 = 0;z<source.bottom;z++, z0++)
  68.             for(int x=source.left, x0 = 0;x<source.right;x++, x0++)
  69.             {
  70.                 //Triangle 1
  71.                 ind[index++] =   z0   * (width + 1) + x0;
  72.                 ind[index++] =   z0   * (width + 1) + x0 + 1;
  73.                 ind[index++] = (z0+1) * (width + 1) + x0;        
  74.  
  75.                 //Triangle 2
  76.                 ind[index++] = (z0+1) * (width + 1) + x0;
  77.                 ind[index++] =   z0   * (width + 1) + x0 + 1;
  78.                 ind[index++] = (z0+1) * (width + 1) + x0 + 1;
  79.             }
  80.  
  81.         m_pMesh->UnlockIndexBuffer();
  82.  
  83.         //Set Attributes
  84.         DWORD *att = 0, a = 0;
  85.         m_pMesh->LockAttributeBuffer(0,&att);
  86.         memset(att, 0, sizeof(DWORD)*nrTri);
  87.         m_pMesh->UnlockAttributeBuffer();
  88.  
  89.         //Compute normals
  90.         D3DXComputeNormals(m_pMesh, NULL);
  91.     }
  92.     catch(...)
  93.     {
  94.         debug.Print("Error in PATCH::CreateMesh()");
  95.         return E_FAIL;
  96.     }
  97.  
  98.     return S_OK;
  99. }
  100.  
  101. void PATCH::Render()
  102. {
  103.     //Draw mesh
  104.     if(m_pMesh != NULL)
  105.         m_pMesh->DrawSubset(0);
  106. }
  107.  
  108. //////////////////////////////////////////////////////////////////////////////////////////
  109. //                                    TERRAIN                                                //
  110. //////////////////////////////////////////////////////////////////////////////////////////
  111.  
  112. TERRAIN::TERRAIN()
  113. {
  114.     m_pDevice = NULL;
  115. }
  116.  
  117. void TERRAIN::Init(IDirect3DDevice9* Dev, INTPOINT _size)
  118. {
  119.     m_pDevice = Dev;
  120.     m_size = _size;
  121.     m_pHeightMap = NULL;
  122.  
  123.     //Load textures
  124.     IDirect3DTexture9* grass = NULL, *mount = NULL, *snow = NULL;
  125.     if(FAILED(D3DXCreateTextureFromFile(Dev, "textures/grass.jpg", &grass)))debug.Print("Could not load grass.jpg");
  126.     if(FAILED(D3DXCreateTextureFromFile(Dev, "textures/mountain.jpg", &mount)))debug.Print("Could not load mountain.jpg");
  127.     if(FAILED(D3DXCreateTextureFromFile(Dev, "textures/snow.jpg", &snow)))debug.Print("Could not load snow.jpg");
  128.     m_diffuseMaps.push_back(grass);
  129.     m_diffuseMaps.push_back(mount);
  130.     m_diffuseMaps.push_back(snow);
  131.  
  132.     //Create white material    
  133.     m_mtrl.Ambient = m_mtrl.Specular = m_mtrl.Diffuse  = D3DXCOLOR(0.5f, 0.5f, 0.5f, 1.0f);
  134.     m_mtrl.Emissive = D3DXCOLOR(0.0f, 0.0f, 0.0f, 1.0f);
  135.  
  136.     GenerateRandomTerrain(3);
  137. }
  138.  
  139. void TERRAIN::Release()
  140. {
  141.     for(int i=0;i<m_patches.size();i++)
  142.         if(m_patches[i] != NULL)
  143.             m_patches[i]->Release();
  144.  
  145.     m_patches.clear();
  146.  
  147.     if(m_pHeightMap != NULL)
  148.     {
  149.         m_pHeightMap->Release();
  150.         delete m_pHeightMap;
  151.         m_pHeightMap = NULL;
  152.     }
  153. }
  154.  
  155. void TERRAIN::GenerateRandomTerrain(int numPatches)
  156. {
  157.     try
  158.     {
  159.         Release();
  160.  
  161.         //Create two heightmaps and multiply them
  162.         m_pHeightMap = new HEIGHTMAP(m_size, 20.0f);
  163.         HEIGHTMAP hm2(m_size, 20.0f);
  164.  
  165.         m_pHeightMap->CreateRandomHeightMap(rand()%2000, 2.0f, 0.7f, 8);
  166.         hm2.CreateRandomHeightMap(rand()%2000, 2.5f, 0.8f, 3);
  167.  
  168.         hm2.Cap(hm2.m_fMaxHeight * 0.4f);
  169.  
  170.         *m_pHeightMap *= hm2;
  171.         hm2.Release();
  172.  
  173.         CreatePatches(numPatches);
  174.         CalculateAlphaMaps();
  175.     }
  176.     catch(...)
  177.     {
  178.         debug.Print("Error in TERRAIN::GenerateRandomTerrain()");
  179.     }
  180. }
  181.  
  182. void TERRAIN::CreatePatches(int numPatches)
  183. {
  184.     try
  185.     {
  186.         //Clear any old m_patches
  187.         for(int i=0;i<m_patches.size();i++)
  188.             if(m_patches[i] != NULL)
  189.                 m_patches[i]->Release();
  190.         m_patches.clear();
  191.  
  192.         if(m_pHeightMap == NULL)return;
  193.  
  194.         //Create new m_patches
  195.         for(int y=0;y<numPatches;y++)
  196.             for(int x=0;x<numPatches;x++)
  197.             {
  198.                 RECT r = {x * (m_size.x - 1) / (float)numPatches, 
  199.                           y * (m_size.y - 1) / (float)numPatches, 
  200.                         (x+1) * (m_size.x - 1) / (float)numPatches,
  201.                         (y+1) * (m_size.y - 1) / (float)numPatches};
  202.                         
  203.                 PATCH *p = new PATCH();
  204.                 p->CreateMesh(*m_pHeightMap, r, m_pDevice);
  205.                 m_patches.push_back(p);
  206.             }
  207.     }
  208.     catch(...)
  209.     {
  210.         debug.Print("Error in TERRAIN::CreatePatches()");
  211.     }
  212. }
  213.  
  214. void TERRAIN::CalculateAlphaMaps()
  215. {
  216.     //Clear old alpha maps
  217.     for(int i=0;i<m_alphaMaps.size();i++)
  218.         if(m_alphaMaps[i] != NULL)
  219.             m_alphaMaps[i]->Release();
  220.     m_alphaMaps.clear();
  221.  
  222.     //height ranges...
  223.     float min_range[] = {0.0f, 1.0f, 15.0f};
  224.  
  225.     //Create one alpha map per diffuse map
  226.     for(int i=0;i<m_diffuseMaps.size();i++)
  227.     {
  228.         //Create new texture
  229.         IDirect3DTexture9* newTexture = NULL;
  230.         D3DXCreateTexture(m_pDevice, 128, 128, 1, D3DUSAGE_DYNAMIC, D3DFMT_A8R8G8B8, D3DPOOL_DEFAULT, &newTexture);
  231.  
  232.         //Lock the texture
  233.         D3DLOCKED_RECT sRect;
  234.         newTexture->LockRect(0, &sRect, NULL, NULL);
  235.         BYTE *bytes = (BYTE*)sRect.pBits;
  236.  
  237.         //For each pixel in the alphaMap
  238.         for(int y=0;y<sRect.Pitch / 4;y++)
  239.             for(int x=0;x<sRect.Pitch / 4;x++)
  240.             {
  241.                 int hm_x = m_pHeightMap->m_size.x * (x / (float)(sRect.Pitch / 4));
  242.                 int hm_y = m_pHeightMap->m_size.y * (y / (float)(sRect.Pitch / 4));
  243.                 float height = m_pHeightMap->m_pHeightMap[hm_x + hm_y * m_pHeightMap->m_size.x];
  244.     
  245.                 //Paint white if the height is within the correct range
  246.                 BYTE *b = bytes + y * sRect.Pitch + x * 4;
  247.                 if(height >= min_range[i])memset(b, 255, 4);
  248.                 else memset(b, 0, 4);
  249.             }
  250.                         
  251.         //Unlock the texture
  252.         newTexture->UnlockRect(0);
  253.         
  254.         //char *fname[] = {"a1.bmp","a2.bmp","a3.bmp"};
  255.         //D3DXSaveTextureToFile(fname[i], D3DXIFF_BMP, newTexture, NULL);
  256.  
  257.         m_alphaMaps.push_back(newTexture);
  258.     }
  259. }
  260.  
  261. void TERRAIN::Render()
  262. {
  263.     //Set render states        
  264.     m_pDevice->SetRenderState(D3DRS_LIGHTING, false);
  265.     m_pDevice->SetRenderState(D3DRS_ZWRITEENABLE, true);    
  266.  
  267.     //Alpha from alphaTextures, stage 0
  268.     m_pDevice->SetTextureStageState(0, D3DTSS_ALPHAOP, D3DTOP_SELECTARG1);
  269.     m_pDevice->SetTextureStageState(0, D3DTSS_ALPHAARG1, D3DTA_TEXTURE);
  270.  
  271.     //Color from textures, stage 1
  272.     m_pDevice->SetTextureStageState(1, D3DTSS_COLOROP, D3DTOP_SELECTARG1);
  273.     m_pDevice->SetTextureStageState(1, D3DTSS_COLORARG1, D3DTA_TEXTURE);
  274.     m_pDevice->SetTextureStageState(1, D3DTSS_ALPHAOP, D3DTOP_SELECTARG1);
  275.     m_pDevice->SetTextureStageState(1, D3DTSS_ALPHAARG1, D3DTA_CURRENT);
  276.  
  277.     //Set blend states
  278.     m_pDevice->SetRenderState(D3DRS_ALPHABLENDENABLE, true);
  279.     m_pDevice->SetRenderState(D3DRS_SRCBLEND, D3DBLEND_SRCALPHA);
  280.     m_pDevice->SetRenderState(D3DRS_DESTBLEND, D3DBLEND_INVSRCALPHA);
  281.  
  282.     m_pDevice->SetMaterial(&m_mtrl);
  283.  
  284.     //Draw mesh once for each terrain type
  285.     for(int i=0;i<m_diffuseMaps.size();i++)
  286.     {
  287.         m_pDevice->SetTexture(0, m_alphaMaps[i]);
  288.         m_pDevice->SetTexture(1, m_diffuseMaps[i]);
  289.         
  290.         for(int p=0;p<m_patches.size();p++)
  291.             m_patches[p]->Render();
  292.     }
  293. }